/**
 * @file elf_parse.c
 * @author etcfly (etcflywy@126.com)
 * @brief 
 * @version 1.0.0
 * @date 2025-07-22
 * 
 * @copyright Copyright (c) 2025
 * 
 */
#include <stdio.h>
#include <stdint.h>
#include "elf_parse.h"


void elf_fileHeader_parse(const char *pfileHeader)
{
    const char *types[] = {"ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE"};
    const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)pfileHeader;
    printf("ELF Header:\r\n\t");
    for (int i = 0; i < sizeof(ehdr->e_ident); i++) {
        printf("%02x ", ehdr->e_ident[i]);
    }
    printf("\r\n");

    printf("\r\nmachine:%s\r\n", ehdr->e_machine == 3 ? "EM_386" : "Other");
    printf("type:%s\r\n", types[ehdr->e_type]);
    printf("version:%s\r\n", ehdr->e_version == 0 ? "EV_NONE" : "EV_CURRENT");
    printf("\r\nelf header len:%d\r\n", ehdr->e_ehsize);
    printf("entry:%#x\r\n", ehdr->e_entry);
    printf("programHeader offset:%#x\r\n", ehdr->e_phoff);
    printf("programEntrySize:%d\r\n", ehdr->e_phentsize);
    printf("programNum:%d\r\n", ehdr->e_phnum);

    printf("sectorOff:%#x\r\n", ehdr->e_shoff);
    printf("sectorEntSize:%d\r\n", ehdr->e_shentsize);
    printf("sectorNum:%d\r\n", ehdr->e_shnum);

    printf("StrSection:%d\r\n", ehdr->e_shstrndx);
    printf("sizeof(elfHeader)=%d\r\n\r\n", sizeof(Elf32_Ehdr));
}

char *section_types_get(Elf32_Word type)
{
    switch (type) {
        case SHT_NULL: return "NULL"; 
        case SHT_PROGBITS: return "PROGBITS"; 
        case SHT_SYMTAB: return "SYMTAB";
        case SHT_STRTAB: return "STRTAB";
        case SHT_RELA: return "RELA";
        case SHT_HASH: return "HASH";
        case SHT_DYNAMIC: return "DYNAMIC";
        case SHT_NOTE: return "NOTE";
        case SHT_NOBITS: return "NOBITS";
        case SHT_REL: return "REL";
        case SHT_SHLIB: return "SHLIB";
        case SHT_DYNSYM: return "DYNSYM";
        case SHT_LOPROC: return "LOPROC";
        case SHT_HIPROC: return "HIPROC";
        case SHT_LOUSER: return "LOUSER";
        case SHT_HIUSER: return "HIUSER";
        case SHT_INIT_ARRAY: return "INIT_ARRAY";
        case SHT_FINI_ARRAY: return "FINI_ARRAY";
        case SHT_PREINIT_ARRAY: return "PREINIT_ARRAY";
        case SHT_GNU_versym: return "VERSYM";
        case SHT_GNU_HASH: return "GUN_HASH";
        case SHT_GNU_verneed: return "VERNEED";
        default: return "Unknow";
    }
    return "Unknow";
}

char *section_flags_get(Elf32_Word flags)
void show_section_entry_info(int index, const Elf32_Shdr *shdr, const char *pstring)
{
    printf("  [%02d] %-18s%-16s%08x %06x %06x %02x   A  %2d   %2d  %2d\r\n", index, &pstring[shdr->sh_name], 
    section_types_get(shdr->sh_type), shdr->sh_addr, shdr->sh_offset, shdr->sh_size, shdr->sh_entsize,
    shdr->sh_link, shdr->sh_info, shdr->sh_addralign);
}



void elf_section_table_parse(const char *pfileHeader)
{
    const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)pfileHeader;
    const Elf32_Shdr *shdr = (const Elf32_Shdr *)(void*)&pfileHeader[ehdr->e_shoff];
    const Elf32_Shdr *shdr_str  = &shdr[ehdr->e_shstrndx];
    const char *pstring = (const char *)&pfileHeader[shdr_str->sh_offset];

    printf("There are %d section headers, starting at offset %#x:\r\n\r\n\
Section Headers:\r\n", ehdr->e_shnum, ehdr->e_entry);
    printf("  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al\r\n");
    for (int i = 0; i < ehdr->e_shnum; i++) {
        show_section_entry_info(i, &shdr[i], pstring);
    }
}

void elf_parse(const char *pfile)
{
    elf_fileHeader_parse(pfile);
    elf_section_table_parse(pfile);
}